package com.example.flower_shop.service;

import com.example.flower_shop.entity.User;
import com.example.flower_shop.enums.UserRole;
import com.example.flower_shop.exception.BusinessException;
import com.example.flower_shop.repository.UserRepository;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;

import java.security.Key;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

@Service
public class JwtService {
    private static final Logger logger = LoggerFactory.getLogger(JwtService.class);

    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.expiration}")
    private Long expiration;

    private final UserRepository userRepository;

    public JwtService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public String extractUsername(String token) {
        return extractClaim(token, Claims::getSubject);
    }

    public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = extractAllClaims(token);
        return claimsResolver.apply(claims);
    }

    public String generateToken(User user) {
        logger.info("开始为用户生成 Token: userId={}, username={}, role={}",
                user.getId(), user.getUsername(), user.getRole());
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", user.getId());
        claims.put("role", user.getRole().name());
        logger.info("Token claims: {}", claims);
        return generateToken(claims, user);
    }

    public String generateToken(Map<String, Object> extraClaims, User user) {
        Date now = new Date(System.currentTimeMillis());
        Date expiryDate = new Date(now.getTime() + expiration);
        logger.info("Token 有效期: {} 到 {}", now, expiryDate);

        String token = Jwts
                .builder()
                .setClaims(extraClaims)
                .setSubject(user.getUsername())
                .setIssuedAt(now)
                .setExpiration(expiryDate)
                .signWith(getSignInKey(), SignatureAlgorithm.HS256)
                .compact();

        logger.info("Token 生成成功: {}", token.substring(0, 10) + "...");
        return token;
    }

    public Authentication getAuthentication(String token) {
        logger.info("开始从 Token 中提取认证信息");
        Claims claims = extractAllClaims(token);
        Long userId = claims.get("userId", Long.class);
        String role = claims.get("role", String.class);
        String username = claims.getSubject();
        logger.info("从 Token 中提取的信息: userId={}, role={}, username={}", userId, role, username);

        // 验证用户是否存在
        userRepository.findById(userId)
                .orElseThrow(() -> {
                    logger.error("无法找到用户: {}", userId);
                    return new BusinessException("USER_NOT_FOUND", "用户不存在");
                });

        Collection<SimpleGrantedAuthority> authorities;
        if ("MERCHANT".equals(role)) {
            authorities = Collections.singletonList(new SimpleGrantedAuthority("MERCHANT"));
        } else {
            authorities = Collections.singletonList(new SimpleGrantedAuthority(role));
        }

        Authentication auth = new UsernamePasswordAuthenticationToken(
                userId,
                null,
                authorities);

        logger.info("创建认证对象: principal={}, authorities={}",
                auth.getPrincipal(), auth.getAuthorities());
        return auth;
    }

    public boolean validateToken(String token) {
        try {
            logger.info("开始验证 Token");
            Claims claims = Jwts.parserBuilder()
                    .setSigningKey(getSignInKey())
                    .build()
                    .parseClaimsJws(token)
                    .getBody();

            logger.info("Token 验证成功，包含的信息: subject={}, userId={}, role={}, expiration={}",
                    claims.getSubject(),
                    claims.get("userId"),
                    claims.get("role"),
                    claims.getExpiration());
            return true;
        } catch (Exception e) {
            logger.error("Token 验证失败: {}", e.getMessage());
            return false;
        }
    }

    private Claims extractAllClaims(String token) {
        return Jwts
                .parserBuilder()
                .setSigningKey(getSignInKey())
                .build()
                .parseClaimsJws(token)
                .getBody();
    }

    private Key getSignInKey() {
        byte[] keyBytes = Decoders.BASE64.decode(secret);
        return Keys.hmacShaKeyFor(keyBytes);
    }
}